Devredilemez Token
Özet
- Orijinal Token Programında, devredilemez (bazen "ruh bağlı" olarak adlandırılan) token oluşturmak imkansızdır.
- Token Uzantı Programı'nın
devredilemez token
uzantısı, devredilemez tokenları etkinleştirir.
Genel Bakış
Token Programında, transfer edilemeyen bir token oluşturmak imkansızdır. Bu, önemsiz gibi görünse de, birinin devredilemez (veya "ruh bağlı") bir token vermek istemesi için birkaç nedeni olabilir.
Ana Fikir: Bir Solana oyun geliştiricisi olarak, "Bits and Bytes" oyununda devredilemez NFT'ler ile başarıları ödüllendirmek isteyebilirsiniz. Bu, oyuncuların başarılarını cüzdanlarında gururla sergilemelerini sağlar. Ancak, bu Token Programında mümkün değildir. Fakat, Token Uzantı Programında mümkündür!
Token Uzantı Programı, devredilemez mintler oluşturmak için kullanılabilecek devredilemez
uzantısına sahiptir. Bu mintler yakılabilir, ancak transfer edilemezler.
Devredilemez mint hesap oluşturma
Devredilemez bir minti başlatmak üç talimat içerir:
SystemProgram.createAccount
createInitializeNonTransferableMintInstruction
createInitializeMintInstruction
İlk talimat olan SystemProgram.createAccount
, mint hesabı için blockchain üzerinde alan ayırır. Bu talimat üç şeyi gerçekleştirir:
alan
ayırır- Kira için
lamport
transfer eder - Kendisi için mülkiyet programını atar
Diğer tüm uzantılar gibi, mint hesabı için gereken alan ve lamportları hesaplamanız gerekecek. Bunu şu şekilde çağırarak yapabilirsiniz: getMintLen
ve getMinimumBalanceForRentExemption
.
const extensions = [ExtensionType.NonTransferable];
const mintLength = getMintLen(extensions);
const mintLamports =
await connection.getMinimumBalanceForRentExemption(mintLength);
const createAccountInstruction = SystemProgram.createAccount({
fromPubkey: payer.publicKey,
newAccountPubkey: mintKeypair.publicKey,
space: mintLength,
lamports: mintLamports,
programId: TOKEN_2022_PROGRAM_ID,
});
İkinci talimat olan createInitializeNonTransferableMintInstruction
devredilemez uzantıyı başlatır.
const initializeNonTransferableMintInstruction =
createInitializeNonTransferableMintInstruction(
mintKeypair.publicKey,
TOKEN_2022_PROGRAM_ID,
);
Üçüncü talimat olan createInitializeMintInstruction
minti başlatır.
const initializeMintInstruction = createInitializeMintInstruction(
mintKeypair.publicKey,
decimals,
payer.publicKey,
null, // Onay Konfigürasyonu
TOKEN_2022_PROGRAM_ID,
);
Son olarak, tüm talimatları bir işlemle ekleyip Solana'ya gönderin.
const mintTransaction = new Transaction().add(
createAccountInstruction,
initializeNonTransferableMintInstruction,
initializeMintInstruction,
);
await sendAndConfirmTransaction(
connection,
mintTransaction,
[payer, mintKeypair],
{ commitment: "finalized" },
);
Ve işte bu! Artık mint hesabınız var ve mint edildiğinde transfer edilemez. Bu uzantı, metadata
ve metadata-pointer
uzantıları ile birleştirildiğinde daha heyecan verici hale gelir ve ruh bağlı NFT'ler oluşturur.
Laboratuvar
Bu laboratuvarda, devredilemez bir token oluşturacağız ve ardından onu transfer etmeyi denediğimizde ne olacağını göreceğiz (ipucu: transfer başarısız olacak).
1. Başlarken
Başlamak için devredilemez-token
adında boş bir dizin oluşturun ve içine geçin. Yepyeni bir proje başlatacağız. npm init
çalıştırın ve yönergeleri izleyin.
Sonraki adımda bağımlılıklarımızı eklememiz gerekecek. Gerekli paketleri yüklemek için aşağıdakini çalıştırın:
npm i @solana-developers/helpers@2 @solana/spl-token @solana/web3.js@1 esrun dotenv typescript
src
adında bir dizin oluşturun. Bu dizinde index.ts
adında bir dosya oluşturun. Bu, bu uzantının kurallarına göre kontroller yapacağımız yerdir. index.ts
'ye aşağıdaki kodu yapıştırın:
import { Connection, Keypair } from "@solana/web3.js";
import { initializeKeypair } from "@solana-developers/helpers";
import dotenv from "dotenv";
import {
createAccount,
mintTo,
TOKEN_2022_PROGRAM_ID,
} from "@solana/spl-token";
// import { createNonTransferableMint } from './create-mint';
dotenv.config();
/**
* Bir bağlantı oluşturun ve eğer yoksa bir anahtar çiftini başlatın.
* Eğer bir anahtar çifti mevcutsa, gerekirse bir SOL airdrop edin.
*/
const connection = new Connection("http://127.0.0.1:8899", "confirmed");
const payer = await initializeKeypair(connection);
console.log(`public key: ${payer.publicKey.toBase58()}`);
const mintKeypair = Keypair.generate();
const mint = mintKeypair.publicKey;
console.log("\nmint public key: " + mintKeypair.publicKey.toBase58() + "\n\n");
// MINT OLUŞTUR
// KAYNAK HESAP OLUŞTUR VE TOKEN BAS
// TRANSFER İÇİN HEDEF HESAP OLUŞTUR
// TRANSFER DENEMESİ
Bu dosya, belirtilen doğrulayıcı düğümüne bir bağlantı oluşturup initializeKeypair
çağıran bir ana işlev içermektedir. Bu ana işlev, yazdıktan sonra betiğimizin diğer kısımlarını çağıracağımız yerdir.
Hemen betiği çalıştırın. Terminalinizde mint
public key'ini göreceksiniz.
esrun src/index.ts
Eğer initializeKeypair
ile airdrop sırasında bir hata ile karşılaşırsanız, bir sonraki adıma geçin.
2. Geliştirici ortamının kurulması (isteğe bağlı)
Eğer devnet SOL ile airdrop sorunları yaşıyorsanız, şu adımları izleyebilirsiniz:
initializeKeypair
'akeypairPath
parametresini ekleyin ve devnet SOL almak için Solana'nın faucet'ini kullanın.- Aşağıdaki şekilde bir yerel doğrulayıcı çalıştırın:
Ayrı bir terminalde aşağıdaki komutu çalıştırın: solana-test-validator
. Bu, düğümü çalıştıracak ve bazı anahtarları ve değerleri günlüğe kaydedecektir. Bağlantımızda kullanmamız gereken değer, bu durumda http://127.0.0.1:8899
olan JSON RPC URL'sidir. Bunu bağlantıda kullanarak yerel RPC URL'sini kullanmayı belirtiyoruz.
const connection = new Connection("http://127.0.0.1:8899", "confirmed");
3. Devredilemez bir mint oluştur
Yeni bir dosyada src/create-mint.ts
içinde createNonTransferableMint
fonksiyonunu oluşturalım.
Dosya içinde, aşağıdaki argümanlarla createNonTransferableMint
fonksiyonunu oluşturun:
connection
: Bağlantı nesnesipayer
: İşlem için ödeme yapanmintKeypair
: Yeni mint için anahtar çiftidecimals
: Mint ondalık sayısı
Fonksiyon içinde, aşağıdakileri çağıracağız:
getMintLen
- mint hesabı için gereken alanı almakgetMinimumBalanceForRentExemption
- mint hesabı için gereken lamport miktarını almakcreateAccount
- mint hesabı için blockchain üzerinde alan ayırmakcreateInitializeNonTransferableMintInstruction
- uzantıyı başlatmakcreateInitializeMintInstruction
- minti başlatmaksendAndConfirmTransaction
- işlemi blockchain'e göndermek
import {
sendAndConfirmTransaction,
Connection,
Keypair,
SystemProgram,
Transaction,
TransactionSignature,
} from "@solana/web3.js";
import {
ExtensionType,
createInitializeMintInstruction,
getMintLen,
TOKEN_2022_PROGRAM_ID,
createInitializeNonTransferableMintInstruction,
} from "@solana/spl-token";
export async function createNonTransferableMint(
connection: Connection,
payer: Keypair,
mintKeypair: Keypair,
decimals: number,
): Promise<TransactionSignature> {
const extensions = [ExtensionType.NonTransferable];
const mintLength = getMintLen(extensions);
const mintLamports =
await connection.getMinimumBalanceForRentExemption(mintLength);
console.log("Devredilemez talimatla bir işlem oluşturuluyor...");
const mintTransaction = new Transaction().add(
SystemProgram.createAccount({
fromPubkey: payer.publicKey,
newAccountPubkey: mintKeypair.publicKey,
space: mintLength,
lamports: mintLamports,
programId: TOKEN_2022_PROGRAM_ID,
}),
createInitializeNonTransferableMintInstruction(
mintKeypair.publicKey,
TOKEN_2022_PROGRAM_ID,
),
createInitializeMintInstruction(
mintKeypair.publicKey,
decimals,
payer.publicKey,
null,
TOKEN_2022_PROGRAM_ID,
),
);
const signature = await sendAndConfirmTransaction(
connection,
mintTransaction,
[payer, mintKeypair],
{ commitment: "finalized" },
);
return signature;
}
Şimdi bu işlevi src/index.ts
içinde çağırarak devredilemez minti oluşturalım:
// MINT OLUŞTUR
const decimals = 9;
await createNonTransferableMint(connection, payer, mintKeypair, decimals);
Betiği hata almadan çalıştırmalısınız.
esrun src/index.ts
Devredilemez mint doğru şekilde ayarlandı ve npm start
çalıştırıldığında oluşturulacaktır. Şimdi bir kaynak hesabı oluşturalım ve buna bir token basmaya geçelim.
4. Token basma
Bu mintten oluşturulan tokenların aslında transfer edilemediğini test edelim. Bunu yapmak için, bir hesaba token basmamız gerekiyor.
Bunu src/index.ts
içinde yapalım. Bir kaynak hesabı oluşturalım ve bir devredilemez token basımında bulunalım.
Bunu iki fonksiyonla başarabiliriz:
getOrCreateAssociatedTokenAccount
:@solana/spl-token
kütüphanesinden, belirtilen mint ve sahip için bir ilişkili token hesabı (ATA) oluşturur.mintTo
: Bu fonksiyon, belirtilen token hesabına belirli birmiktar
kadar token basar.
// ÖDEYİCİ ATA OLUŞTUR VE TOKEN BAS
console.log("İlişkili Token Hesabı oluşturuluyor...");
const ata = (
await getOrCreateAssociatedTokenAccount(
connection,
payer,
mint,
payer.publicKey,
undefined,
undefined,
undefined,
TOKEN_2022_PROGRAM_ID,
)
).address;
console.log("1 token basılıyor...");
const amount = 1 * 10 ** decimals;
await mintTo(
connection,
payer,
mint,
ata,
payer,
amount,
[payer],
{ commitment: "finalized" },
TOKEN_2022_PROGRAM_ID,
);
const tokenBalance = await connection.getTokenAccountBalance(ata, "finalized");
console.log(
`Hesap ${ata.toBase58()} şimdi ${tokenBalance.value.uiAmount} token ile bulunmaktadır.`,
);
Betiği çalıştırın ve bir tokenın bir hesaba basıldığını doğrulayın:
esrun src/index.ts
5. Devredilemez tokenı transfer etmeyi deneme
Son olarak, tokenı başka bir yere transfer etmeye çalışalım. Öncelikle bir token hesabı oluşturmalıyız ve ardından transfer etmeyi denemek istiyoruz.
src/index.ts
içinde, bir hedef hesap oluşturacağız ve devredilemez tokenı bu hesaba transfer etmeyi deneyelim.
Bunu iki fonksiyonla başarabiliriz:
createAccount
: Bu, belirtilen mint ve bu hesabın anahtar çifti için bir token hesabı oluşturur. Bu yüzden burada bir ATA kullanmak yerine yeni bir anahtar çifti oluşturacağız. Farklı seçenekleri göstermek için bunu yapıyoruz.transferChecked
: Bu, token transfer etmeyi deneyecektir.
Öncelikle createAccount
fonksiyonu:
// TRANSFER İÇİN HEDEF HESAP OLUŞTUR
console.log("Bir hedef hesap oluşturuluyor...\n\n");
const destinationKeypair = Keypair.generate();
const destinationAccount = await createAccount(
connection,
payer,
mintKeypair.publicKey,
destinationKeypair.publicKey,
undefined,
{ commitment: "finalized" },
TOKEN_2022_PROGRAM_ID,
);
Şimdi, transferChecked
fonksiyonu:
// TRANSFER DENEMESİ
console.log("Devredilemez mintı transfer etmeye çalışıyor...");
try {
const signature = await transferChecked(
connection,
payer,
ata,
mint,
destinationAccount,
ata,
amount,
decimals,
[destinationKeypair],
{ commitment: "finalized" },
TOKEN_2022_PROGRAM_ID,
);
} catch (e) {
console.log(
"Bu transfer, mint devredilemez olduğu için başarısız oluyor. Program günlüklerini kontrol edin: ",
(e as any).logs,
"\n\n",
);
}
Şimdi her şeyi çalıştırın ve ne olacağını görelim:
esrun src/index.ts
Sonunda Transfer is disabled for this mint
şeklinde bir hata mesajı almalıydınız. Bu, transfer etmeye çalıştığımız token'ın gerçekten devredilemez olduğunu gösteriyor!
Devredilemez mintı transfer etmeye çalışıyor...
Bu transfer, mint devredilemez olduğu için başarısız oluyor. Program günlüklerini kontrol edin: [
'Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [1]',
'Program log: Instruction: TransferChecked',
'Program log: Transfer is disabled for this mint',
'Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 3910 of 200000 compute units',
'Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb failed: custom program error: 0x25'
]
Bu kadar! Başarıyla devredilemez bir mint oluşturdunuz. Eğer herhangi bir noktada takılırsanız, çalışır durumda olan kodu bu depo solution
dalında bulabilirsiniz.
Meydan Okuma
Meydan okuma için, kendi devredilemez tokenınızı oluşturun ve metadata uzantısını ekleyerek bir “ruh bağlı” NFT'yi kendinize tutun.